【数据挖掘比赛】TalkingData AdTracking Fraud Detection Challenge

TalkingData AdTracking Fraud Detection Challenge 是 TalkingData 在 Kaggle 上举办的一个数据挖掘比赛。最终取得的成绩是 Solo 银牌

这个比赛历程比较有趣,应该可以说是我时间花费最少的比赛吧。最开始关注到这个比赛是 4 月 25 日,那时我便随便下载了个别人的结果提交,当时排名 300+,于是我就置之不理了。之后再开始做的时候已经是 5 月 2 日了,排名也掉到了 1100+。从 5 月 2 日至 5 月 7 日,我大概只用了 6 天(期间还有在忙其他的事情,因此也不是全脱产比赛),幸运的拿到一枚银牌。下图是我比赛期间的排名变化。

公榜排名变化

因为时间较短,我的结果都是来自于单模型 LightGBM,并没有尝试其他模型。因此我会分享比赛中我认为比较重要的两个部分:亿级数据的处理特征构建

项目源码:https://github.com/ShawnyXiao/2018-Kaggle-AdTrackingFraud

亿级数据的处理

该比赛提供的数据大约 10 G,有超过 1 亿个样本。如何利用有限的内存来处理这 10 G 的数据,对于这个比赛是十分关键的。比赛中,我大致使用过以下几个操作:

  1. 使用 Pandas 读取数据时,如果没有指定每列的数据类型,它会以最保守的方式来读取:使用 uint64 读取非负整型,使用 float64 读取浮点数和带空值的整型。如果使用这种最保守的方式读取数据,带来的内存消耗是极大的。因此,使用适当的数据类型 uint8uint16uint34float32 等来读取数据,能够很好的节约我们的内存资源。
  2. 很多变量我们在之后不会再使用了,但是如果一直被保存在内存中,也会耗费我们极为珍贵的内存资源。因此,当某个变量 a(尤其占较大内存的变量)不再使用时,我们应该及时将它从内存中删除:del a
  3. 我们经常会使用某个变量引用不同的对象,这时会产生一些无法再继续引用的对象,理论上 Python 会自动帮我们做垃圾回收,但是需要触发某些条件。因此,我们可以经常性的调用函数:gc.collect(),来触发垃圾回收操作。
  4. 对于类别特征,我们一般会进行 One-hot 转换。如果不转换,模型会把类别特征当作有序的连续值来处理;如果转化了,特征维度会变得极大,内存耗费增大的同时模型的训练速度也会减慢。LightGBM 对于类别特征做了优化处理,只需要在准备数据时指定类别特征即可,这样不需要再对类别特征进行 One-hot 转换,因此不会增大内存耗费也不会减慢模型的训练速度。

特征构建

特征构建部分对于提分尤为关键。特征构建可以被分解成两个问题:基于什么数据集去构建特征构建哪些特征

1. 基于什么数据集去构建特征?

最开始的时候,对于比赛方提供 test_supplement 这个数据集的意图不是特别清楚,因此没有使用该数据。使用 train+test 这个数据集来构建特征,分数不高也不低,公榜 0.9800,在铜牌的位置;后来尝试使用了 train+test_supplement 这个数据集来构建特征,分数直接上升一个千公榜 0.9813,在银牌的位置!因此,从这个现象我们可以察觉,从 train+test 提取的特征训练的模型的偏差(bias)是比 train+test_supplement 要大不少的。

2. 构建哪些特征?

  1. 基于 [ip, app, channel, device, os] 分组后,计算后一个的时间差
  2. 基于 [ip, os, device] 分组后,计算后一个的时间差
  3. 基于 [ip, os, device, app] 分组后,计算后一个的时间差
  4. 基于 [ip, channel] 分组后,计算前一个的时间差
  5. 基于 [ip, os] 分组后,计算前一个的时间差
  6. 基于 [ip] 分组后,统计 channel 的 unique 数量
  7. 基于 [ip, device, os] 分组后,统计 app 的 unique 数量
  8. 基于 [ip, day] 分组后,统计 hour 的 unique 数量
  9. 基于 [ip] 分组后,统计 app 的 unique 数量
  10. 基于 [ip, app] 分组后,统计 os 的 unique 数量
  11. 基于 [ip] 分组后,统计 device 的 unique 数量
  12. 基于 [app] 分组后,统计 channel 的 unique 数量
  13. 基于 [ip] 分组后,统计 os 的 cumcount 计数
  14. 基于 [ip, device, os] 分组后,统计 app 的 cumcount 计数
  15. 基于 [ip, day, hour] 分组后,统计数量
  16. 基于 [ip, app] 分组后,统计数量
  17. 基于 [ip, app, os] 分组后,统计数量
  18. 基于 [ip, app, os] 分组后,统计 day 的方差
  19. 基于不同分组的转化率特征(这个最后没时间做了,据说可以提升 5 个万分点)

嘿!

如果您有任何的想法,例如:发现某处有 bug、觉得我对某个方法的讲解不正确或者不透彻、有更加有创意的见解,欢迎随时发 issue 或者 pull request 或者直接与我讨论!另外您若能 star 或者 fork 这个项目以激励刚刚踏入数据挖掘的我,我会感激不尽~